## JS 原型

MDN 定义：[JS 原型是什么？](https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object_prototypes)  
1.原型是一种继承机制，js 就是采用的这种机制。  
每个对象拥有一个原型对象，对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型，并从中继承方法和属性，一层一层、以此类推。这种关系常被称为原型链 (prototype chain)，它解释了为何一个对象会拥有定义在其他对象中的属性和方法。

JavaScript 原型是参考 Self 语言实现的。Self 是 Smalltalk 语言的一种变体，是一种基于原型的面向对象编程语言。JavaScript 的创始人 Brendan Eich 也参考了 Self 语言的原型继承机制，将其运用到 JavaScript 中实现了原型继承。

## **proto**属性

\_\_proto\_\_：然而，大多数现代浏览器还是提供了一个名为 \_\_proto\_\_ （前后各有 2 个下划线）的属性，其包含了对象的原型。你可以尝试输入 person1.\_\_proto\_\_ 和 person1.\_\_proto\_\_.\_\_proto\_\_，看看代码中的原型链是什么样的！

当创建一个对象时，JavaScript 引擎会为其分配一个隐藏的**proto**属性，指向该对象的原型。当我们访问对象的属性或方法时，如果在对象本身中找不到，JavaScript 引擎会沿着原型链向上查找。
例如，如果我们创建一个对象 person，它的原型是 Object.prototype：

```js
let person = {
  name: "Alice",
};
console.log(person.toString()); // "[object Object]"
```

虽然 person 对象本身没有 toString()方法，但是在沿着原型链向上查找的过程中，JavaScript 引擎会在 Object.prototype 中找到该方法，因此 person 对象可以调用 toString()方法并正确返回结果。

原型机制是 JavaScript 中实现继承的基础。通过定义原型，我们可以将一些常用的属性和方法共享到各个实例对象中，从而实现代码的复用和优化。同时，通过原型链的方式，我们也可以实现多层继承，以便更加灵活地处理各种业务需求。

## prototype

prototype 是原型对象，会自动添加到函数上面。每声明一个函数都会有个 prototype 属性。

## [[prototype]]

[[prototype]]：没有官方的方法用于直接访问一个对象的原型对象——原型链中的“连接”被定义在一个内部属性中，在 JavaScript 语言标准中用 [[prototype]] 表示（参见 ECMAScript）。  
你可能会认为，this 关键字指向当前对象的原型对象，其实不是（还记得么？原型对象是一个内部对象，应当使用 \_\_\_proto\_\_ 访问）。prototype 属性包含（指向）一个对象，你在这个对象中定义需要被继承的成员。

:::tip
Object 的 3 种数据属性：命名属性，访问器属性，内部属性[[]]  
所有对象共有的内部属性有12个：  
[[Prototype]],[[Class]],[[Extensible]],[[Get]],[[GetOwnProperty]],[[GetProperty]],[[Put]],[[CanPut]],[[HasProperty]],[[Delete]],  
[[DefaultValue]],[[DefineOwnProperty]]  
 通用 12 个内部属性前 3 个可用来指示对象本身的一些特性，后 9 个可对对象进行特定的操作，它们在进行相应的操作时会自动调用，只是对象本书哪些特性？后面九歌可对对象进行特定的操作。
除了共有的 12 个以外，不同的对象会有不同的内部属性 Function 类型的[[HasInstance]],RegExp[[Match]].
:::

## 总结

- 每一个类都是一个显示原型 prototype
- 每一个类都有一个隐式原型**\_\_proto\_\_**
- 实例的\_\_proto\_\_等于类的显示原型 prototype
- 当去查找一个实例的属性或方法，先在自身查找，找不到则沿着**proto**向上查找
- 我们把原型**proto**与原型**proto**形成的链条关系叫做原型链
- 作用是：实现了 JS 的继承，让实列拥有了类的公用方法

## 继承方式：

### 原型链继承

原型链继承是 JavaScript 中最常用的继承方式之一，通过将子类的原型对象指向父类的实例来实现继承，使子类可以继承父类的属性和方法。例如

```js
function Parent() {
  this.name = "parent";
}
function Child() {
  this.name = "child";
}
Parent.prototype.sayHello = function () {
  return "Hello, " + this.name;
};

Child.prototype = new Parent();

console.log(new Child().name); // child
console.log(new Child().sayHello()); // Hello，child
```

### 构造函数继承

是指在子类的构造函数中调用父类的构造函数，从而继承父类的属性和方法。

```js
function Parent() {
  this.name = "parent";
  this.sayHello = function () {
    return "Hello, " + this.name;
  };
}

function Child() {
  Parent.call(this);
}
console.log(new Child().name); // parent
console.log(new Child().sayHello()); // Hello，parent
```

### 组合继承

是将原型链继承和构造函数继承结合起来，既可以继承父类的原型属性和方法，又可以继承父类的实例属性和方法。

```js
function Parent() {
  this.name = "parent";
  this.sayHello = function () {
    return "Hello, " + this.name;
  };
}

function Child() {
  Parent.call(this);
  this.name = "child";
}

Child.prototype = new Parent();
Child.prototype.constructor = Child;

console.log(new Child().name); // child
console.log(new Child().sayHello()); // Hello，child
```

### 原型式继承

是指通过创建一个临时构造函数来继承一个对象，并将这个构造函数的原型指向这个对象，从而实现继承。

```js
function createObject(obj) {
  function F() {}
  F.prototype = obj;
  return new F();
}

var parent = {
  name: "parent",
  sayHello() {
    return "Hello, " + this.name;
  },
};

var child = createObject(parent);
child.name = "child";

console.log(child.name); // child
console.log(child.sayHello()); // Hello，child
```

### 寄生式继承

是在原型式继承的基础上，对继承的对象进行扩展，从而形成一个新的对象。

```js
function createObject(obj) {
  var o = Object.create(obj);
  o.sayHello = function () {
    return "Hello, " + this.name;
  };
  return o;
}

var parent = {
  name: "parent",
};

var child = createObject(parent);
child.name = "child";

console.log(child.name); // child
console.log(child.sayHello()); // Hello，child
```

### 寄生组合式继承

是通过创建一个临时构造函数，将父类的原型赋值给子类的原型，从而实现继承，同时使用 Object.create() 方法将子类的原型与父类的原型关联起来，从而避免了不必要的父类构造函数调用。

```js
function inherit(subClass, superClass) {
  function F() {}
  F.prototype = superClass.prototype;


```
